/*
 *  Platform abstraction layer
 *
 *  Copyright The Mbed TLS Contributors
 *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 *
 *  This file is provided under the Apache License 2.0, or the
 *  GNU General Public License v2.0 or later.
 *
 *  **********
 *  Apache License 2.0:
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
 *  not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  **********
 *
 *  **********
 *  GNU General Public License v2.0 or later:
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *  **********
 */

#if !defined(MBEDTLS_CONFIG_FILE)
#include "nettls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif

#if defined(MBEDTLS_PLATFORM_C)

#include "nettls/platform.h"
#include "nettls/platform_util.h"

/* The compile time configuration of memory allocation via the macros
 * MBEDTLS_PLATFORM_{FREE/CALLOC}_MACRO takes precedence over the runtime
 * configuration via mbedtls_platform_set_calloc_free(). So, omit everything
 * related to the latter if MBEDTLS_PLATFORM_{FREE/CALLOC}_MACRO are defined. */
#if defined(MBEDTLS_PLATFORM_MEMORY) && !(defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && defined(MBEDTLS_PLATFORM_FREE_MACRO))

#if !defined(MBEDTLS_PLATFORM_STD_CALLOC)
static void* platform_calloc_uninit(size_t n, size_t size)
{
    ((void)n);
    ((void)size);
    return (NULL);
}

#define MBEDTLS_PLATFORM_STD_CALLOC platform_calloc_uninit
#endif /* !MBEDTLS_PLATFORM_STD_CALLOC */

#if !defined(MBEDTLS_PLATFORM_STD_FREE)
static void platform_free_uninit(void* ptr)
{
    ((void)ptr);
}

#define MBEDTLS_PLATFORM_STD_FREE platform_free_uninit
#endif /* !MBEDTLS_PLATFORM_STD_FREE */

static void* (*mbedtls_calloc_func)(size_t, size_t) = MBEDTLS_PLATFORM_STD_CALLOC;
static void (*mbedtls_free_func)(void*) = MBEDTLS_PLATFORM_STD_FREE;

void* mbedtls_calloc(size_t nmemb, size_t size)
{
    return (*mbedtls_calloc_func)(nmemb, size);
}

void mbedtls_free(void* ptr)
{
    (*mbedtls_free_func)(ptr);
}

int mbedtls_platform_set_calloc_free(void* (*calloc_func)(size_t, size_t), void (*free_func)(void*))
{
    mbedtls_calloc_func = calloc_func;
    mbedtls_free_func = free_func;
    return (0);
}
#endif /* MBEDTLS_PLATFORM_MEMORY && \
          !( defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && \
             defined(MBEDTLS_PLATFORM_FREE_MACRO) ) */

#if defined(_WIN32)
#include <stdarg.h>
int mbedtls_platform_win32_snprintf(char* s, size_t n, const char* fmt, ...)
{
    int ret;
    va_list argp;

    /* Avoid calling the invalid parameter handler by checking ourselves */
    if (s == NULL || n == 0 || fmt == NULL)
        return (-1);

    va_start(argp, fmt);
#if defined(_TRUNCATE) && !defined(__MINGW32__)
    ret = _vsnprintf_s(s, n, _TRUNCATE, fmt, argp);
#else
    ret = _vsnprintf(s, n, fmt, argp);
    if (ret < 0 || (size_t)ret == n) {
        s[n - 1] = '\0';
        ret = -1;
    }
#endif
    va_end(argp);

    return (ret);
}
#endif

#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)

int (*mbedtls_snprintf)(char* s, size_t n, const char* format, ...) = MBEDTLS_PLATFORM_STD_SNPRINTF;

int mbedtls_platform_set_snprintf(int (*snprintf_func)(char* s, size_t n, const char* format, ...))
{
    mbedtls_snprintf = snprintf_func;
    return (0);
}
#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */

#if !defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT)
/*
 * Placeholder platform setup that does nothing by default
 */
int mbedtls_platform_setup(mbedtls_platform_context* ctx)
{
    (void)ctx;

    return (0);
}

/*
 * Placeholder platform teardown that does nothing by default
 */
void mbedtls_platform_teardown(mbedtls_platform_context* ctx)
{
    (void)ctx;
}
#endif /* MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */

#endif /* MBEDTLS_PLATFORM_C */
